﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace PrisonStep
{
    public class SpitFire
    {
        public class Spit
        {
            private float radius = 11;
            public float Radius { get { return radius; } }
            private float velocity = 600f;
            public float Velocity { get { return velocity; } set { velocity = value; } }
            private Matrix transform;
            public Matrix Transform { get { return transform; } set { transform = value; } }
            private String oldRegion;
            public String OldRegion { get { return oldRegion; } set { oldRegion = value; } }

            public Spit(Matrix alienTransform)
            {
                transform = alienTransform;
            }
        }

        private LinkedList<Spit> spits = new LinkedList<Spit>();
        private Model spitModel;
        private PrisonGame game;
        private PhibesModel phibesModel;

        public SpitFire(PhibesModel phibesModel, PrisonGame game)
        {
            this.game = game;
            this.phibesModel = phibesModel;
        }

        public void LoadContent(ContentManager content)
        {
            spitModel = content.Load<Model>("Spit");
        }

        public void Update(GameTime gameTime, Player victoria)
        {
            for (LinkedListNode<Spit> spitNode = spits.First; spitNode != null; )
            {
                LinkedListNode<Spit> nextSpit = spitNode.Next;
                Spit spit = spitNode.Value;

                Vector3 offset = Vector3.TransformNormal(new Vector3(-1, 0, 0), spit.Transform)
                        * spit.Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
                spit.Transform = spit.Transform * Matrix.CreateTranslation(offset);

                //If the spit went outside of the rooms and doors - delete it
                //I allow spit to travel through closed doors since it is acid
                if (phibesModel.TestRegion(spit.Transform.Translation) == "")
                {
                    spits.Remove(spitNode);
                }
                //determine if the spit hit Victoria 
                //if there is a hit, subtract 100 points
                else if (victoria.testCollisionSphere(spit.Radius, spit.Transform.Translation))
                {
                    victoria.SlimeHit = true;
                    spits.Remove(spitNode);
                    victoria.GameScore -= 100;
                }

                spitNode = nextSpit;
            }
        }

        public void Fire(Matrix alienTransform, float spitOrientation, Vector3 spitStartPosition)
        {
            Spit spit = new Spit(alienTransform);
            //set the region
            spit.OldRegion = phibesModel.TestRegion(spit.Transform.Translation);
            spits.AddLast(spit);
        }

        public void Draw(GraphicsDeviceManager graphics, GameTime gameTime)
        {
            //draw the spit
            //graphics.BlendState = BlendState.AlphaBlend; //Lecture 14, slide 28, does not work
            game.Graphics.GraphicsDevice.BlendState = BlendState.AlphaBlend;
            foreach (Spit spit in spits)
            {
                DrawModel(graphics, spitModel, spit.Transform);
            }
            game.Graphics.GraphicsDevice.BlendState = BlendState.Opaque;
        }

        private void DrawModel(GraphicsDeviceManager graphics, Model model, Matrix world)
        {
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = transforms[mesh.ParentBone.Index] * world;
                    effect.View = game.Camera.View;
                    effect.Projection = game.Camera.Projection;
                }
                mesh.Draw();
            }
        }
    }
}
